package fox.framework.rpc.common;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author cuichao
 * @Description: ReflectionUtils
 * @Date: create in 2021/1/13 15:31
 */
public class ReflectionUtils {



    /**
     * 找到可访问的方法
     * @param source
     * @return
     */
    public static List<Method> getAccessibleMethods(Class<?> source){
        Method[] methods = source.getMethods();
        List<Method> list = new ArrayList<>();
        for (Method method : methods) {

            if(!Modifier.isPublic(method.getModifiers())){
                continue;
            }
            if(isObjectMethod(method)){
                continue;
            }
            list.add(method);
        }
        return list;
    }




    /**
     * 获取该类锁实现的所有接口
     *
     * @param source
     * @return
     */
    public static List<Class<?>> getAllInterface(Class<?> source) {
        List<Class<?>> list = new ArrayList<>();
        Class<?>[] interfaces = source.getInterfaces();
        for (Class<?> inter : interfaces) {
            list.add(inter);
            list.addAll(getAllInterface(inter));
        }
        return list;
    }


    /**
     * 找到目标带有指定注解的Class集合
     *
     * @param source
     * @param annotationClass
     * @return
     */
    public static List<Class<?>> getInterfacesWithAnnotation(Class<?> source, Class annotationClass) {
        return getInterfacesWithAnnotation(source, annotationClass, false);
    }


    /**
     * 找到目标带有指定注解的Class集合
     *
     * @param source          需要查找的类
     * @param annotationClass 指定注解的类
     * @param inherit         找到目标类后是否继续查找其父类
     * @return
     */
    public static List<Class<?>> getInterfacesWithAnnotation(Class<?> source, Class annotationClass, boolean inherit) {
        if (!annotationClass.isAnnotation()) {
            String msg = String.format("{} is not annotation class", annotationClass);
            throw new IllegalArgumentException(msg);
        }
        List<Class<?>> list = new ArrayList<>();
        Class<?>[] interfaces = source.getInterfaces();
        for (Class<?> inter : interfaces) {
            Annotation annotation = inter.getAnnotation(annotationClass);
            if (annotation != null) {
                list.add(inter);
                if (inherit) {
                    list.addAll(getInterfacesWithAnnotation(inter, annotationClass, inherit));
                }
            } else {
                list.addAll(getInterfacesWithAnnotation(inter, annotationClass, inherit));
            }
        }
        return list;
    }


    /**
     * 找到接口默认的方法
     *
     * @param clazz
     * @return
     */
    private static List<Method> findConcreteMethodsOnInterfaces(Class<?> clazz) {
        List<Method> result = null;
        for (Class<?> ifc : clazz.getInterfaces()) {
            for (Method ifcMethod : ifc.getMethods()) {
                if (!Modifier.isAbstract(ifcMethod.getModifiers())) {
                    if (result == null) {
                        result = new ArrayList<>();
                    }
                    result.add(ifcMethod);
                }
            }
        }
        return result;
    }



    public static List<Method> excludeStaticOrFinalMethod(List<Method> methods){
        return methods.stream().filter(v -> {
            if ( !Modifier.isStatic(v.getModifiers()) &&  !Modifier.isFinal(v.getModifiers()) ){
                return true;
            }
            return false;
        }).collect(Collectors.toList());
    }


    /**
     * 判断方法是否是静态的或者final继承的
     * @param field
     * @return
     */
    public static boolean isPublicStaticFinal(Field field) {
        int modifiers = field.getModifiers();
        return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers));
    }


    /**
     * 是否Object原生方法
     *
     * @param method
     * @return
     */
    public static boolean isObjectMethod(Method method) {
        return (method != null && (method.getDeclaringClass() == Object.class ||
                isEqualsMethod(method) || isHashCodeMethod(method) || isToStringMethod(method)));
    }

    /**
     * 是否是equals方法
     *
     * @param method
     * @return
     */
    public static boolean isEqualsMethod(Method method) {
        if (method == null || !method.getName().equals("equals")) {
            return false;
        }
        if (method.getParameterCount() != 1) {
            return false;
        }
        return method.getParameterTypes()[0] == Object.class;
    }

    /**
     * 是否是hashcode方法
     *
     * @param method
     * @return
     */
    public static boolean isHashCodeMethod(Method method) {
        return (method != null && method.getName().equals("hashCode") && method.getParameterCount() == 0);
    }

    /**
     * 是否是toString方法
     *
     * @param method
     * @return
     */
    public static boolean isToStringMethod(Method method) {
        return (method != null && method.getName().equals("toString") && method.getParameterCount() == 0);
    }

    /**
     * 方法参数是否和给定的数组匹配
     *
     * @param method
     * @param paramTypes
     * @return
     */
    private static boolean hasSameParams(Method method, Class<?>[] paramTypes) {
        return (paramTypes.length == method.getParameterCount() && Arrays.equals(paramTypes, method.getParameterTypes()));
    }

    /**
     * 设置方法对象Accessible 为true
     *
     * @param method
     */
    public static void makeAccessible(Method method) {
        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
            method.setAccessible(true);
        }
    }
}

